package com.cencat.common.utils;

import com.cencat.common.constants.CommonConstants;
import com.cencat.common.enums.ErrorCode;
import com.cencat.common.exception.BusinessException;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

/**
 * 文件上传工具类
 * 提供统一的文件上传、下载和管理功能
 * 
 * @author cencat
 * @since 2024-01-01
 */
public class FileUploadUtils {
    
    private static final Logger log = LoggerFactory.getLogger(FileUploadUtils.class);

    /**
     * 私有构造函数，防止实例化
     */
    private FileUploadUtils() {
        throw new UnsupportedOperationException("Utility class cannot be instantiated");
    }

    /**
     * 默认上传路径
     */
    private static final String DEFAULT_UPLOAD_PATH = "uploads";

    /**
     * 日期格式化器
     */
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd");

    /**
     * 允许的图片文件类型
     */
    private static final List<String> ALLOWED_IMAGE_TYPES = Arrays.asList(
            "image/jpeg", "image/jpg", "image/png", "image/gif", "image/bmp", "image/webp"
    );

    /**
     * 允许的文档文件类型
     */
    private static final List<String> ALLOWED_DOCUMENT_TYPES = Arrays.asList(
            "application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation",
            "text/plain", "text/csv"
    );

    /**
     * 上传文件
     * 
     * @param file 上传的文件
     * @param uploadPath 上传路径
     * @return 文件上传结果
     * @throws BusinessException 业务异常
     */
    public static FileUploadResult uploadFile(MultipartFile file, String uploadPath) throws BusinessException {
        // 参数校验
        if (file == null || file.isEmpty()) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "上传文件不能为空");
        }

        // 文件大小校验
        validateFileSize(file);

        // 文件类型校验
        validateFileType(file);

        // 生成文件路径
        String filePath = generateFilePath(file, uploadPath);

        try {
            // 创建目录
            Path targetPath = Paths.get(filePath);
            Files.createDirectories(targetPath.getParent());

            // 保存文件
            file.transferTo(targetPath.toFile());

            // 构建返回结果
            FileUploadResult result = new FileUploadResult();
            result.setOriginalName(file.getOriginalFilename());
            result.setFileName(targetPath.getFileName().toString());
            result.setFilePath(filePath);
            result.setFileSize(file.getSize());
            result.setContentType(file.getContentType());
            result.setUploadTime(LocalDateTime.now());
            result.setRelativePath(getRelativePath(filePath));

            log.info("文件上传成功: originalName={}, fileName={}, filePath={}", 
                    result.getOriginalName(), result.getFileName(), result.getFilePath());

            return result;

        } catch (IOException e) {
            log.error("文件上传失败: {}", e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED, "文件上传失败: " + e.getMessage());
        }
    }

    /**
     * 上传文件（使用默认路径）
     * 
     * @param file 上传的文件
     * @return 文件上传结果
     * @throws BusinessException 业务异常
     */
    public static FileUploadResult uploadFile(MultipartFile file) throws BusinessException {
        return uploadFile(file, DEFAULT_UPLOAD_PATH);
    }

    /**
     * 上传图片文件
     * 
     * @param file 上传的图片文件
     * @param uploadPath 上传路径
     * @return 文件上传结果
     * @throws BusinessException 业务异常
     */
    public static FileUploadResult uploadImage(MultipartFile file, String uploadPath) throws BusinessException {
        // 图片类型校验
        if (!isImageFile(file)) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "只允许上传图片文件");
        }

        // 图片大小校验
        if (file.getSize() > CommonConstants.File.MAX_IMAGE_SIZE) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, 
                    "图片文件大小不能超过" + (CommonConstants.File.MAX_IMAGE_SIZE / 1024 / 1024) + "MB");
        }

        return uploadFile(file, uploadPath + "/images");
    }

    /**
     * 上传图片文件（使用默认路径）
     * 
     * @param file 上传的图片文件
     * @return 文件上传结果
     * @throws BusinessException 业务异常
     */
    public static FileUploadResult uploadImage(MultipartFile file) throws BusinessException {
        return uploadImage(file, DEFAULT_UPLOAD_PATH);
    }

    /**
     * 删除文件
     * 
     * @param filePath 文件路径
     * @return 是否删除成功
     */
    public static boolean deleteFile(String filePath) {
        if (CencatStringUtils.isBlank(filePath)) {
            return false;
        }

        try {
            Path path = Paths.get(filePath);
            boolean deleted = Files.deleteIfExists(path);
            
            if (deleted) {
                log.info("文件删除成功: {}", filePath);
            } else {
                log.warn("文件不存在或删除失败: {}", filePath);
            }
            
            return deleted;
        } catch (IOException e) {
            log.error("文件删除失败: filePath={}, error={}", filePath, e.getMessage(), e);
            return false;
        }
    }

    /**
     * 检查文件是否存在
     * 
     * @param filePath 文件路径
     * @return 是否存在
     */
    public static boolean fileExists(String filePath) {
        if (CencatStringUtils.isBlank(filePath)) {
            return false;
        }
        return Files.exists(Paths.get(filePath));
    }

    /**
     * 获取文件大小
     * 
     * @param filePath 文件路径
     * @return 文件大小（字节）
     */
    public static long getFileSize(String filePath) {
        if (CencatStringUtils.isBlank(filePath)) {
            return 0;
        }

        try {
            return Files.size(Paths.get(filePath));
        } catch (IOException e) {
            log.error("获取文件大小失败: filePath={}, error={}", filePath, e.getMessage());
            return 0;
        }
    }

    /**
     * 获取文件扩展名
     * 
     * @param fileName 文件名
     * @return 文件扩展名
     */
    public static String getFileExtension(String fileName) {
        if (CencatStringUtils.isBlank(fileName)) {
            return "";
        }

        int lastDotIndex = fileName.lastIndexOf('.');
        if (lastDotIndex == -1 || lastDotIndex == fileName.length() - 1) {
            return "";
        }

        return fileName.substring(lastDotIndex + 1).toLowerCase();
    }

    /**
     * 生成唯一文件名
     * 
     * @param originalFileName 原始文件名
     * @return 唯一文件名
     */
    public static String generateUniqueFileName(String originalFileName) {
        String extension = getFileExtension(originalFileName);
        String uuid = UUID.randomUUID().toString().replace("-", "");
        
        if (CencatStringUtils.isNotBlank(extension)) {
            return uuid + "." + extension;
        }
        
        return uuid;
    }

    /**
     * 校验文件大小
     * 
     * @param file 文件
     * @throws BusinessException 业务异常
     */
    private static void validateFileSize(MultipartFile file) throws BusinessException {
        if (file.getSize() > CommonConstants.File.MAX_FILE_SIZE) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, 
                    "文件大小不能超过" + (CommonConstants.File.MAX_FILE_SIZE / 1024 / 1024) + "MB");
        }
    }

    /**
     * 校验文件类型
     * 
     * @param file 文件
     * @throws BusinessException 业务异常
     */
    private static void validateFileType(MultipartFile file) throws BusinessException {
        String contentType = file.getContentType();
        if (CencatStringUtils.isBlank(contentType)) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "无法识别文件类型");
        }

        // 检查是否为允许的文件类型
        boolean isAllowed = ALLOWED_IMAGE_TYPES.contains(contentType) || 
                           ALLOWED_DOCUMENT_TYPES.contains(contentType);
        
        if (!isAllowed) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "不支持的文件类型: " + contentType);
        }
    }

    /**
     * 判断是否为图片文件
     * 
     * @param file 文件
     * @return 是否为图片文件
     */
    private static boolean isImageFile(MultipartFile file) {
        String contentType = file.getContentType();
        return contentType != null && ALLOWED_IMAGE_TYPES.contains(contentType);
    }

    /**
     * 生成文件路径
     * 
     * @param file 文件
     * @param uploadPath 上传路径
     * @return 文件路径
     */
    private static String generateFilePath(MultipartFile file, String uploadPath) {
        // 生成日期路径
        String datePath = LocalDateTime.now().format(DATE_FORMATTER);
        
        // 生成唯一文件名
        String uniqueFileName = generateUniqueFileName(file.getOriginalFilename());
        
        // 组合完整路径
        return Paths.get(uploadPath, datePath, uniqueFileName).toString();
    }

    /**
     * 获取相对路径
     * 
     * @param fullPath 完整路径
     * @return 相对路径
     */
    private static String getRelativePath(String fullPath) {
        // 简单处理，实际项目中可能需要更复杂的逻辑
        return fullPath.replace("\\", "/");
    }

    /**
     * 文件上传结果
     */
    public static class FileUploadResult {
        /**
         * 原始文件名
         */
        private String originalName;

        /**
         * 存储文件名
         */
        private String fileName;

        /**
         * 文件完整路径
         */
        private String filePath;

        /**
         * 文件相对路径
         */
        private String relativePath;

        /**
         * 文件大小（字节）
         */
        private Long fileSize;

        /**
         * 文件类型
         */
        private String contentType;

        /**
         * 上传时间
         */
        private LocalDateTime uploadTime;

        // Getter methods
        public String getOriginalName() {
            return originalName;
        }

        public String getFileName() {
            return fileName;
        }

        public String getFilePath() {
            return filePath;
        }

        public String getRelativePath() {
            return relativePath;
        }

        public Long getFileSize() {
            return fileSize;
        }

        public String getContentType() {
            return contentType;
        }

        public LocalDateTime getUploadTime() {
            return uploadTime;
        }

        // Setter methods
        public void setOriginalName(String originalName) {
            this.originalName = originalName;
        }

        public void setFileName(String fileName) {
            this.fileName = fileName;
        }

        public void setFilePath(String filePath) {
            this.filePath = filePath;
        }

        public void setRelativePath(String relativePath) {
            this.relativePath = relativePath;
        }

        public void setFileSize(Long fileSize) {
            this.fileSize = fileSize;
        }

        public void setContentType(String contentType) {
            this.contentType = contentType;
        }

        public void setUploadTime(LocalDateTime uploadTime) {
            this.uploadTime = uploadTime;
        }

        /**
         * 获取文件大小（MB）
         */
        public double getFileSizeMB() {
            return fileSize == null ? 0 : fileSize / 1024.0 / 1024.0;
        }

        /**
         * 获取文件扩展名
         */
        public String getFileExtension() {
            return FileUploadUtils.getFileExtension(originalName);
        }
    }
}